From 28d7f497efef3fe80b9ad6a76f344ee3a862eaf9 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 30 Aug 2020 21:48:00 -0400 Subject: [PATCH] togglebutton: Add grouping This is the replacement for groups of radiobuttons with draw-indicator = FALSE. --- docs/reference/gtk/gtk4-sections.txt | 1 + gtk/gtktogglebutton.c | 129 +++++++++++++++++++++++++++ gtk/gtktogglebutton.h | 4 + 3 files changed, 134 insertions(+) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 2199592314..8083e9aada 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -3322,6 +3322,7 @@ gtk_toggle_button_new_with_mnemonic gtk_toggle_button_toggled gtk_toggle_button_get_active gtk_toggle_button_set_active +gtk_toggle_button_set_group GTK_TOGGLE_BUTTON diff --git a/gtk/gtktogglebutton.c b/gtk/gtktogglebutton.c index bb6a3e8adf..edce7e0368 100644 --- a/gtk/gtktogglebutton.c +++ b/gtk/gtktogglebutton.c @@ -101,6 +101,9 @@ typedef struct _GtkToggleButtonPrivate GtkToggleButtonPrivate; struct _GtkToggleButtonPrivate { + GtkToggleButton *group_next; + GtkToggleButton *group_prev; + guint active : 1; }; @@ -112,6 +115,7 @@ enum { enum { PROP_0, PROP_ACTIVE, + PROP_GROUP, NUM_PROPERTIES }; @@ -134,6 +138,9 @@ gtk_toggle_button_set_property (GObject *object, case PROP_ACTIVE: gtk_toggle_button_set_active (tb, g_value_get_boolean (value)); break; + case PROP_GROUP: + gtk_toggle_button_set_group (GTK_TOGGLE_BUTTON (object), g_value_get_object (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -187,6 +194,50 @@ gtk_toggle_button_clicked (GtkButton *button) gtk_toggle_button_set_active (toggle_button, !priv->active); } +static void +gtk_toggle_button_dispose (GObject *object) +{ + GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (object); + + gtk_toggle_button_set_group (toggle_button, NULL); + + G_OBJECT_CLASS (gtk_toggle_button_parent_class)->dispose (object); +} + +static GtkToggleButton * +get_group_next (GtkToggleButton *self) +{ + return ((GtkToggleButtonPrivate *)gtk_toggle_button_get_instance_private (self))->group_next; +} + +static GtkToggleButton * +get_group_prev (GtkToggleButton *self) +{ + return ((GtkToggleButtonPrivate *)gtk_toggle_button_get_instance_private (self))->group_prev; +} + +static GtkToggleButton * +get_group_first (GtkToggleButton *self) +{ + GtkToggleButton *group_first = NULL; + GtkToggleButton *iter; + + /* Find first in group */ + iter = self; + while (iter) + { + group_first = iter; + + iter = get_group_prev (iter); + if (!iter) + break; + } + + g_assert (group_first); + + return group_first; +} + static void gtk_toggle_button_class_init (GtkToggleButtonClass *class) { @@ -194,6 +245,7 @@ gtk_toggle_button_class_init (GtkToggleButtonClass *class) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); GtkButtonClass *button_class = GTK_BUTTON_CLASS (class); + gobject_class->dispose = gtk_toggle_button_dispose; gobject_class->set_property = gtk_toggle_button_set_property; gobject_class->get_property = gtk_toggle_button_get_property; @@ -210,6 +262,13 @@ gtk_toggle_button_class_init (GtkToggleButtonClass *class) FALSE, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); + toggle_button_props[PROP_GROUP] = + g_param_spec_object ("group", + P_("Group"), + P_("The toggle button whose group this widget belongs to."), + GTK_TYPE_TOGGLE_BUTTON, + GTK_PARAM_WRITABLE); + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, toggle_button_props); /** @@ -313,6 +372,21 @@ gtk_toggle_button_set_active (GtkToggleButton *toggle_button, if (priv->active == is_active) return; + if (is_active && (priv->group_prev || priv->group_next)) + { + GtkToggleButton *group_first = NULL; + GtkToggleButton *iter; + + group_first = get_group_first (toggle_button); + g_assert (group_first); + + /* Set all buttons in group to !active */ + for (iter = group_first; iter; iter = get_group_next (iter)) + gtk_toggle_button_set_active (iter, FALSE); + + /* ... and the next code block will set this one to active */ + } + priv->active = is_active; if (is_active) @@ -363,3 +437,58 @@ gtk_toggle_button_toggled (GtkToggleButton *toggle_button) g_signal_emit (toggle_button, toggle_button_signals[TOGGLED], 0); } + +/** + * gtk_toggle_button_set_group: + * @self: a #GtkToggleButton + * @group: (nullable) (transfer none): another #GtkToggleButton to + * form a group with + * + * Adds @self to the group of @group. In a group of multiple toggle buttons, + * only one button can be active at a time. + */ +void +gtk_toggle_button_set_group (GtkToggleButton *self, + GtkToggleButton *group) +{ + GtkToggleButtonPrivate *priv = gtk_toggle_button_get_instance_private (self); + GtkToggleButtonPrivate *group_priv = gtk_toggle_button_get_instance_private (group); + + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (self)); + + if (!group) + { + if (priv->group_prev) + { + GtkToggleButtonPrivate *p = gtk_toggle_button_get_instance_private (priv->group_prev); + p->group_next = priv->group_next; + } + if (priv->group_next) + { + GtkToggleButtonPrivate *p = gtk_toggle_button_get_instance_private (priv->group_next); + p->group_prev = priv->group_prev; + } + + priv->group_next = NULL; + priv->group_prev = NULL; + g_object_notify_by_pspec (G_OBJECT (self), toggle_button_props[PROP_GROUP]); + return; + } + + if (priv->group_next == group) + return; + + priv->group_prev = NULL; + if (group_priv->group_prev) + { + GtkToggleButtonPrivate *prev = gtk_toggle_button_get_instance_private (group_priv->group_prev); + + prev->group_next = self; + priv->group_prev = group_priv->group_prev; + } + + group_priv->group_prev = self; + priv->group_next = group; + + g_object_notify_by_pspec (G_OBJECT (self), toggle_button_props[PROP_GROUP]); +} diff --git a/gtk/gtktogglebutton.h b/gtk/gtktogglebutton.h index 8f5923d9b2..44219bb106 100644 --- a/gtk/gtktogglebutton.h +++ b/gtk/gtktogglebutton.h @@ -79,6 +79,10 @@ GDK_AVAILABLE_IN_ALL gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button); GDK_AVAILABLE_IN_ALL void gtk_toggle_button_toggled (GtkToggleButton *toggle_button); +GDK_AVAILABLE_IN_ALL +void gtk_toggle_button_set_group (GtkToggleButton *toggle_button, + GtkToggleButton *group); + G_END_DECLS -- 2.30.2